﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Mesuro.Graphing;
using Mesuro.Common;
using System.ComponentModel;

namespace Mesuro.GUI {
	/// <summary>
	/// Interaction logic for PlotChannelMap.xaml
	/// </summary>
	public partial class PlotChannelMap : UserControl {

		#region DP: Axes
		public static readonly DependencyProperty AxisSetProperty = DependencyProperty.RegisterAttached( "AxisSet", typeof( AxisSetDefinition ), typeof( PlotChannelMap ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.None, AxisSetChangedStatic ) );
		public AxisSetDefinition AxisSet {
			get { return (AxisSetDefinition)GetValue( AxisSetProperty ); }
			set { SetValue( AxisSetProperty, value ); }
		}
		public static AxisSetDefinition GetAxisSet( DependencyObject element ) { return (AxisSetDefinition)element.GetValue( AxisSetProperty ); }
		public static void SetAxisSet( DependencyObject element, AxisSetDefinition value ) { element.SetValue( AxisSetProperty, value ); }
		private static void AxisSetChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { }
		#endregion

		#region DP: Plot
		public static readonly DependencyProperty PlotProperty = DependencyProperty.RegisterAttached( "Plot", typeof( Plot ), typeof( PlotChannelMap ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.None, PlotChangedStatic ) );
		public Plot Plot {
			get { return (Plot)GetValue( PlotProperty ); }
			set { SetValue( PlotProperty, value ); }
		}
		public static Plot GetPlot( DependencyObject element ) { return (Plot)element.GetValue( PlotProperty ); }
		public static void SetPlot( DependencyObject element, Plot value ) { element.SetValue( PlotProperty, value ); }
		private static void PlotChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) {
			PlotChannelMap pcm = sender as PlotChannelMap;
			if (pcm != null)
				pcm.OnPlotChanged( (Plot)e.OldValue, (Plot)e.NewValue );
		}
		#endregion

		public PlotChannelMap() {
			InitializeComponent();
		}

		protected void OnPlotChanged( Plot oldValue, Plot newValue ) {
			itemsControl.Items.Clear();
			if (newValue != null) {
				//Find Axes:
				DependencyObject dObj = VisualTreeHelper.GetParent( newValue );

				while (!(dObj is Axes) && dObj != null)
					dObj = VisualTreeHelper.GetParent( dObj );

				if (dObj == null) return;

				Axes axes = dObj as Axes;
				//Get the approriate axis set:
				AxisSet = MultiAxes.GetAxisSetDefinitions( axes )[MultiAxes.GetAxisSet( newValue )];

				int i = 0;
				foreach (AxisDefinition def in AxisSet.Axes) {
					itemsControl.Items.Add( new PlotAxisDescriptor() { Index = i++, Plot = newValue } );
				}
			}
		}

	}
	public class PlotAxisDescriptor : INotifyPropertyChanged {
		private IList<AxisSetDefinition> axisSets;
		private AxisSetDefinition axisSet;

		//Inputs

		private Plot _plot;
		public Plot Plot {
			get { return _plot; }
			set { Plot oldPlot = _plot; _plot = value; PlotChanged( oldPlot ); }
		}

		private int _index;
		public int Index {
			get { return _index; }
			set { _index = value; IndexChanged(); }
		}

		//Outputs
		public string AxisName { get { return axisSet.Axes[Index].AxisName; } }
		public IEnumerable<IChannelRef> Channels { get { return DataSet.PreferredChannels; } }
		public IChannelRef MappedTo {
			get { return Plot.ChannelMap[Index]; }
			set {
				Plot.ChannelMap[Index] = value;
				PropertyChanged( this, new PropertyChangedEventArgs( "MappedTo" ) );
			}
		}

		//Functions

		private void AxesChanged() {
			Axes Axes = Graph.GetAxes( Plot );
			if (Axes == null) return;

			axisSets = MultiAxes.GetAxisSetDefinitions( Axes );

			if (Plot == null) return;

			axisSet = axisSets[MultiAxes.GetAxisSet( Plot )];

			if (PropertyChanged != null) {
				PropertyChanged( this, new PropertyChangedEventArgs( "AxisName" ) );
			}
		}
		private void PlotChanged( Plot oldPlot ) {
			if (oldPlot != null)
				MultiAxes.RemoveAxisSetChangedHandler( oldPlot, PlotAxisSetChanged );

			AxesChanged();

			if (axisSets == null || Plot == null) return;

			axisSet = axisSets[MultiAxes.GetAxisSet( Plot )];
			MultiAxes.AddAxisSetChangedHandler( Plot, PlotAxisSetChanged );

			if (PropertyChanged != null) {
				PropertyChanged( this, new PropertyChangedEventArgs( "AxisName" ) );
				PropertyChanged( this, new PropertyChangedEventArgs( "MappedTo" ) );
			}
		}
		private void IndexChanged() {
			if (axisSets == null || Plot == null) return;

			axisSet = axisSets[MultiAxes.GetAxisSet( Plot )];

			if (PropertyChanged != null) {
				PropertyChanged( this, new PropertyChangedEventArgs( "AxisName" ) );
				PropertyChanged( this, new PropertyChangedEventArgs( "MappedTo" ) );
			}
		}

		private void PlotAxisSetChanged( object sender, RoutedPropertyChangedEventArgs<int> e ) {
			AxesChanged();
		}

		public event PropertyChangedEventHandler PropertyChanged;
	}
}
